package com.cxc.distributed.demo;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.UUID;

/**
 * 基于redis方式获取分布式锁以及释放分布式锁
 */
public class LockRedis {

    private JedisPool jedisPool;
    private String lockKey = "redis_lock";

    public LockRedis(JedisPool jedisPool){
        this.jedisPool=jedisPool;
    }
    //redis实现分布式锁 有两个超时时间问题
    /**
     * 两个超时时间含义：
     * 1.在获取锁之前的超时时间:在尝试获取锁的时候，如果在规定的时间内还没有获取锁，直接放弃。
     * 2.在获取锁之后的超时时间:当获取锁成功之后，对应的key 有对应有效期，对应的key 在规定时间内进行失效,避免死锁
     */
    public String getRedisDistributedLock(Long acquireTimeout,Long timeOut){

        Jedis conn = null;

        try{
            conn = jedisPool.getResource();
            //定义 redis对应key的value值( uuid) 作用释放锁随机生成value
            String idValue = UUID.randomUUID().toString();
            // 定义在获取锁之后的超时时间
            int expireLock = (int) (timeOut / 1000);// 以秒为单位
            // 使用循环方式重试的获取锁
            Long endTime = System.currentTimeMillis() + acquireTimeout;
            while (System.currentTimeMillis() < endTime) {
                // 获取锁
                // 使用setnx命令插入对应的redislockKey ，如果返回为1 成功获取锁
                if (conn.setnx(lockKey, idValue) == 1) {
                    // 设置对应key的有效期
                    conn.expire(lockKey, expireLock);//为什么获取锁之后，还要设置锁的超时时间 目的是为了防止死锁
                    return idValue;
                }
                // zookeeper实现分布式锁通过什么方式 防止死锁 设置session 有效期
            }

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (null != conn) {
                conn.close();
            }
        }
        return null;
    }

    //释放锁
    public void unRedisLock(String idValue) {
        Jedis conn = null;
        // 1.建立redis连接
        conn = jedisPool.getResource();
        try {
            // 如果该锁的id 等于identifierValue 是同一把锁情况才可以删除
            if (conn.get(lockKey).equals(idValue)) {
                System.out.println("释放锁..." + Thread.currentThread().getName() + ",idValue:" + idValue);
                conn.del(lockKey);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.close();
            }
        }
        // 释放锁有两种 key自动有有效期
        // 整个程序执行完毕情况下，删除对应key

    }

}
